home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / proc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-15  |  19.7 KB  |  893 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* routines for handling processes */
  8.  
  9. #include "mint.h"
  10. #include "xbra.h"
  11.  
  12. static void do_wakeup_things P_((int sr, int newslice));
  13.  
  14. extern short proc_clock;
  15.  
  16. /* global process variables */
  17. PROC *proclist;            /* list of all active processes */
  18. PROC *curproc;            /* current process        */
  19. PROC *rootproc;            /* pid 0 -- MiNT itself        */
  20. PROC *sys_q[NUM_QUEUES];
  21.  
  22. short time_slice = 2;        /* default; actual value comes from mint.cnf */
  23.  
  24. #if 0
  25. #define TIME_SLICE    2    /* number of 20ms ticks before process is
  26.                    pre-empted */
  27. #else
  28. #define TIME_SLICE time_slice
  29. #endif
  30.  
  31. /* macro for calculating number of missed time slices, based on a
  32.  * process' priority
  33.  */
  34. #define SLICES(pri)    (((pri) >= 0) ? 0 : -(pri))
  35.  
  36. extern FILESYS bios_filesys;
  37.  
  38. /*
  39.  * get a new process struct
  40.  */
  41.  
  42. PROC *
  43. new_proc()
  44. {
  45.     PROC *p;
  46.     void *pt;
  47.  
  48.     pt = kmalloc(page_table_size + 16);
  49.     if (!pt) return 0;
  50.  
  51.     p = (PROC *)kmalloc(SIZEOF(PROC));
  52.     if (!p) {
  53.         kfree(pt);
  54.         return 0;
  55.     }
  56. /* page tables must be on 16 byte boundaries, so we
  57.  * round off by 16 for that; however, we will want to
  58.  * kfree that memory at some point, so we squirrel
  59.  * away the original address for later use
  60.  */
  61.     p->page_table = ROUND16(pt);
  62.     p->pt_mem = pt;
  63.     return p;
  64. }
  65.  
  66. /*
  67.  * dispose of an old proc
  68.  */
  69.  
  70. void
  71. dispose_proc(p)
  72.     PROC *p;
  73. {
  74. TRACELOW(("dispose_proc"));
  75.     kfree(p->pt_mem);
  76.     kfree(p);
  77. }
  78.  
  79. /*
  80.  * create a new process that is (practically) a duplicate of the
  81.  * current one
  82.  */
  83.  
  84. PROC *
  85. fork_proc()
  86. {
  87.     PROC *p;
  88.     int i;
  89.     FILEPTR *f;
  90.     long_desc *pthold;
  91.     void *ptmemhold;
  92.  
  93.     if ((p = new_proc()) == 0) {
  94. nomem:
  95.         DEBUG(("fork_proc: insufficient memory"));
  96.         mint_errno = ENSMEM; return 0;
  97.     }
  98.  
  99. /* child shares most things with parent, but hold on to page table ptr */
  100.     pthold = p->page_table;
  101.     ptmemhold = p->pt_mem;
  102.     *p = *curproc;
  103.     p->page_table = pthold;
  104.     p->pt_mem = ptmemhold;
  105.  
  106. /* these things are not inherited */
  107.     p->ppid = curproc->pid;
  108.     p->pid = newpid();
  109.     p->sigpending = 0;
  110.     p->nsigs = 0;
  111.     p->sysstack = (long)(p->stack + STKSIZE - 12);
  112.     p->ctxt[CURRENT].ssp = p->sysstack;
  113.     p->ctxt[SYSCALL].ssp = (long)(p->stack + ISTKSIZE);
  114.     p->alarmtim = 0;
  115.     p->curpri = p->pri;
  116.     p->slices = SLICES(p->pri);
  117.     p->starttime = timestamp;
  118.     p->startdate = datestamp;
  119.     p->itimer[0].interval = 0;
  120.     p->itimer[0].reqtime = 0;
  121.     p->itimer[0].timeout = 0;
  122.     p->itimer[1].interval = 0;
  123.     p->itimer[1].reqtime = 0;
  124.     p->itimer[1].timeout = 0;
  125.     p->itimer[2].interval = 0;
  126.     p->itimer[2].reqtime = 0;
  127.     p->itimer[2].timeout = 0;
  128.  
  129.     ((long *)p->sysstack)[1] = FRAME_MAGIC;
  130.     ((long *)p->sysstack)[2] = 0;
  131.     ((long *)p->sysstack)[3] = 0;
  132.  
  133.     p->usrtime = p->systime = p->chldstime = p->chldutime = 0;
  134.  
  135. /* allocate space for memory regions: do it here so that we can fail
  136.  * before we duplicate anything else. The memory regions are
  137.  * actually copied later
  138.  */
  139.     p->mem = (MEMREGION **) kmalloc(p->num_reg * SIZEOF(MEMREGION *));
  140.     if (!p->mem) {
  141.         dispose_proc(p);
  142.         goto nomem;
  143.     }
  144.     p->addr = (virtaddr *)kmalloc(p->num_reg * SIZEOF(virtaddr));
  145.     if (!p->addr) {
  146.         kfree(p->mem);
  147.         dispose_proc(p);
  148.         goto nomem;
  149.     }
  150.  
  151. /* copy open handles */
  152.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  153.         if ((f = p->handle[i]) != 0) {
  154.             if (f == (FILEPTR *)1 || f->flags & O_NOINHERIT)
  155.         /* oops, we didn't really want to copy this handle */
  156.                 p->handle[i] = 0;
  157.             else
  158.                 f->links++;
  159.         }
  160.     }
  161.  
  162. /* copy root and current directories */
  163.     for (i = 0; i < NUM_DRIVES; i++) {
  164.         dup_cookie(&p->root[i], &curproc->root[i]);
  165.         dup_cookie(&p->curdir[i], &curproc->curdir[i]);
  166.     }
  167.  
  168. /* jr: copy ploadinfo */
  169.     strncpy(p->cmdlin, curproc->cmdlin, 128);
  170.     strcpy(p->fname, curproc->fname);
  171.  
  172. /* clear directory search info */
  173.     zero((char *)p->srchdta, NUM_SEARCH * SIZEOF(DTABUF *));
  174.     zero((char *)p->srchdir, SIZEOF(p->srchdir));
  175.     p->searches = 0;
  176.  
  177. /* copy memory */
  178.     for (i = 0; i < curproc->num_reg; i++) {
  179.         p->mem[i] = curproc->mem[i];
  180.         if (p->mem[i] != 0)
  181.             p->mem[i]->links++;
  182.         p->addr[i] = curproc->addr[i];
  183.     }
  184.  
  185. /* now that memory ownership is copied, fill in page table */
  186.     init_page_table(p);
  187.  
  188. /* child isn't traced */
  189.     p->ptracer = 0;
  190.     p->ptraceflags = 0;
  191.  
  192.     p->starttime = Tgettime();
  193.     p->startdate = Tgetdate();
  194.  
  195.     p->q_next = 0;
  196.     p->wait_q = 0;
  197.     p->gl_next = proclist;
  198.     proclist = p;            /* hook into the process list */
  199.     return p;
  200. }
  201.  
  202. /*
  203.  * initialize the process table
  204.  */
  205.  
  206. void
  207. init_proc()
  208. {
  209.     int i;
  210.     FILESYS *fs;
  211.     fcookie dir;
  212.     long_desc *pthold;
  213.     void *ptmemhold;
  214.  
  215.     rootproc = curproc = new_proc();
  216.     assert(curproc);
  217.  
  218.     pthold = curproc->page_table;
  219.     ptmemhold = curproc->pt_mem;
  220.     zero((char *)curproc, (long)sizeof(PROC));
  221.     curproc->page_table = pthold;
  222.     curproc->pt_mem = ptmemhold;
  223.  
  224.     curproc->ppid = -1;        /* no parent */
  225.     curproc->domain = DOM_TOS;    /* TOS domain */
  226.     curproc->sysstack = (long) (curproc->stack+STKSIZE-12);
  227.     curproc->magic = CTXT_MAGIC;
  228.     curproc->memflags = F_PROT_S;    /* default prot mode: super-only */
  229.     ((long *)curproc->sysstack)[1] = FRAME_MAGIC;
  230.     ((long *)curproc->sysstack)[2] = 0;
  231.     ((long *)curproc->sysstack)[3] = 0;
  232.  
  233. /* NOTE: in main.c this could be changed, later */
  234.     curproc->base = _base;
  235.  
  236.     strcpy(curproc->name, "MiNT");
  237.  
  238. /* get some memory */
  239.     curproc->mem = (MEMREGION **)kmalloc(NUM_REGIONS*SIZEOF(MEMREGION *));
  240.     curproc->addr = (virtaddr *)kmalloc(NUM_REGIONS*SIZEOF(virtaddr));
  241.     assert(curproc->mem && curproc->addr);
  242.  
  243. /* make sure it's filled with zeros */
  244.     zero((char *)curproc->addr, NUM_REGIONS * SIZEOF(virtaddr));
  245.     zero((char *)curproc->mem, NUM_REGIONS * SIZEOF(MEMREGION *));
  246.     curproc->num_reg = NUM_REGIONS;
  247.  
  248. /* get root and current directories for all drives */
  249.     for (i = 0; i < NUM_DRIVES; i++) {
  250.         if ((fs = drives[i]) != 0 && (*fs->root)(i, &dir) == E_OK) {
  251.                 dup_cookie(&curproc->curdir[i], &dir);
  252.                 curproc->root[i] = dir;
  253.         } else {
  254.             curproc->root[i].fs = curproc->curdir[i].fs = 0;
  255.             curproc->root[i].dev = curproc->curdir[i].dev = i;
  256.         }
  257.     }
  258.  
  259.     init_page_table(curproc);
  260.  
  261. /* Set the correct drive. The current directory we
  262.  * set later, after all file systems have been loaded.
  263.  */
  264.  
  265.     curproc->curdrv = Dgetdrv();
  266.     proclist = curproc;
  267.  
  268.     curproc->umask = 0;
  269.  
  270. /*
  271.  * some more protection against job control; unless these signals are
  272.  * re-activated by a shell that knows about job control, they'll have
  273.  * no effect
  274.  */
  275.     curproc->sighandle[SIGTTIN] = curproc->sighandle[SIGTTOU] =
  276.         curproc->sighandle[SIGTSTP] = SIG_IGN;
  277.  
  278. /* set up some more per-process variables */
  279.     curproc->starttime = Tgettime();
  280.     curproc->startdate = Tgetdate();
  281.     if (has_bconmap)
  282. /* init_xbios not happened yet */
  283.         curproc->bconmap = (int) Bconmap(-1);
  284.     else
  285.         curproc->bconmap = 1;
  286.  
  287.     curproc->logbase = (void *)Logbase();
  288.     curproc->criticerr = *((long ARGS_ON_STACK (**) P_((long)))0x404L);
  289. }
  290.  
  291. /*
  292.  * reset all process priorities to their base level
  293.  * called once per second, so that cpu hogs can get _some_ time
  294.  * slices :-).
  295.  */
  296.  
  297. void
  298. reset_priorities()
  299. {
  300.     PROC *p;
  301.  
  302.     for (p = proclist; p; p = p->gl_next) {
  303.         if (p->slices >= 0) {
  304.             p->curpri = p->pri;
  305.             p->slices = SLICES(p->curpri);
  306.         }
  307.     }
  308. }
  309.  
  310. /*
  311.  * more priority code stuff:
  312.  * run_next(p, slices): schedule process "p" to run next, with "slices"
  313.  *       initial time slices; "p" does not actually start running until
  314.  *       the next context switch
  315.  * fresh_slices(slices): give the current process "slices" more slices in
  316.  *       which to run
  317.  */
  318.  
  319. void
  320. run_next(p, slices)
  321.     PROC *p;
  322.     int slices;
  323. {
  324.     short sr = spl7();
  325.     p->slices = -slices;
  326.     p->curpri = MAX_NICE;
  327.     p->wait_q = READY_Q;
  328.     p->q_next = sys_q[READY_Q];
  329.     sys_q[READY_Q] = p;
  330.     spl(sr);
  331. }
  332.  
  333. void
  334. fresh_slices(slices)
  335.     int slices;
  336. {
  337.     reset_priorities();
  338.     curproc->slices = 0;
  339.     curproc->curpri = MAX_NICE+1;
  340.     proc_clock = TIME_SLICE+slices;
  341. }
  342.  
  343. /*
  344.  * add a process to a wait (or ready) queue.
  345.  *
  346.  * processes go onto a queue in first in-first out order
  347.  */
  348.  
  349. void
  350. add_q(que, proc)
  351.     int que;
  352.     PROC *proc;
  353. {
  354.     PROC *q, **lastq;
  355.  
  356. /* "proc" should not already be on a list */
  357.     assert(proc->wait_q == 0);
  358.     assert(proc->q_next == 0);
  359.  
  360.     lastq = &sys_q[que];
  361.     q = *lastq;
  362.     while(q) {
  363.         lastq = &q->q_next;
  364.         q = *lastq;
  365.     }
  366.     *lastq = proc;
  367.     proc->wait_q = que;
  368.     if (que != READY_Q && proc->slices >= 0) {
  369.         proc->curpri = proc->pri;    /* reward the process */
  370.         proc->slices = SLICES(proc->curpri);
  371.     }
  372. }
  373.  
  374. /*
  375.  * remove a process from a queue
  376.  */
  377.  
  378. void
  379. rm_q(que, proc)
  380.     int que;
  381.     PROC *proc;
  382. {
  383.     PROC *q;
  384.     PROC *old = 0;
  385.  
  386.     assert(proc->wait_q == que);
  387.  
  388.     q = sys_q[que];
  389.     while (q && q != proc) {
  390.         old = q;
  391.         q = q->q_next;
  392.     }
  393.     if (q == 0)
  394.         FATAL("rm_q: unable to remove process from queue");
  395.  
  396.     if (old)
  397.         old->q_next = proc->q_next;
  398.     else
  399.         sys_q[que] = proc->q_next;
  400.  
  401.     proc->wait_q = 0;
  402.     proc->q_next = 0;
  403. }
  404.  
  405. /*
  406.  * preempt(): called by the vbl routine and/or the trap handlers when
  407.  * they detect that a process has exceeded its time slice and hasn't
  408.  * yielded gracefully. For now, it just does sleep(READY_Q); later,
  409.  * we might want to keep track of statistics or something.
  410.  */
  411.  
  412. void ARGS_ON_STACK
  413. preempt()
  414. {
  415.     extern short bconbsiz;    /* in bios.c */
  416.  
  417.     if (bconbsiz)
  418.         (void)bflush();
  419.     else {
  420.         /* punish the pre-empted process */
  421.         if (curproc->curpri >= MIN_NICE)
  422.             curproc->curpri -= 1;
  423.     }
  424.     sleep(READY_Q, curproc->wait_cond);
  425. }
  426.  
  427. /*
  428.  * sleep(que, cond): put the current process on the given queue, then switch
  429.  * contexts. Before a new process runs, give it a fresh time slice. "cond"
  430.  * is the condition for which the process is waiting, and is placed in
  431.  * curproc->wait_cond
  432.  */
  433.  
  434. INLINE static void
  435. do_wakeup_things(sr, newslice)
  436. int sr;
  437. int newslice;
  438. {
  439. /*
  440.  * check for stack underflow, just in case
  441.  */
  442.     auto int foo;
  443.     PROC *p;
  444.  
  445.     p = curproc;
  446.  
  447.     if ((sr & 0x700) < 0x500) {
  448. /* skip all this if int level is too high */
  449.         if ( p->pid != 0 &&
  450.              ((long)&foo) < (long)p->stack + ISTKSIZE + 512 ) {
  451.             ALERT("stack underflow");
  452.             handle_sig(SIGBUS);
  453.         }
  454.  
  455. /* see if process' time limit has been exceeded */
  456.  
  457.         if (p->maxcpu) {
  458.             if (p->maxcpu <= p->systime + p->usrtime) {
  459.                 DEBUG(("cpu limit exceeded"));
  460.                 raise(SIGXCPU);
  461.             }
  462.         }
  463.  
  464. /*
  465.  * check for alarms and similar time out stuff (see timeout.c)
  466.  */
  467.  
  468.         checkalarms();
  469.         if (p->sigpending)
  470.             check_sigs();        /* check for signals */
  471.     }
  472.  
  473.     if (newslice) {
  474.         if (p->slices >= 0) {
  475.             proc_clock = TIME_SLICE;    /* get a fresh time slice */
  476.         } else {
  477.             proc_clock = TIME_SLICE-p->slices; /* slices set by run_next */
  478.             p->curpri = p->pri;
  479.         }
  480.         p->slices = SLICES(p->curpri);
  481.     }
  482.     p->slices = SLICES(p->curpri);
  483. }
  484.  
  485. static long sleepcond, iwakecond;
  486.  
  487. /*
  488.  * sleep: returns 1 if no signals have happened since our last sleep, 0
  489.  * if some have
  490.  */
  491.  
  492. int ARGS_ON_STACK 
  493. sleep(_que, cond)
  494.     int _que;
  495.     long cond;
  496. {
  497.     PROC *p;
  498.     short sr, que = _que & 0xff;
  499.     ulong onsigs = curproc->nsigs;
  500.     extern short kintr;    /* in bios.c */
  501.     int newslice = 1;
  502. #ifndef MULTITOS
  503. #ifdef FASTTEXT
  504.     extern int hardscroll;    /* in fasttext.c */
  505. #endif
  506. #endif
  507.  
  508. /* save condition, checkbttys may just wake() it right away...
  509.  * note this assumes the condition will never be waked from interrupts
  510.  * or other than thru wake() before we really went to sleep, otherwise
  511.  * use the 0x100 bit like select
  512.  */
  513.     sleepcond = cond;
  514.  
  515. /*
  516.  * if there have been keyboard interrupts since our last sleep, check for
  517.  * special keys like CTRL-ALT-Fx
  518.  */
  519.  
  520.     sr = spl7();
  521.     if ((sr & 0x700) < 0x500) {
  522. /* can't call checkkeys if sleep was called with interrupts off  -nox */
  523.         spl(sr);
  524.         (void)checkbttys();
  525.         if (kintr) {
  526.             (void)checkkeys();
  527.             kintr = 0;
  528.         }
  529.         sr = spl7();
  530.         if ((curproc->sigpending & ~(curproc->sigmask)) &&
  531.             curproc->pid && que != ZOMBIE_Q && que != TSR_Q) {
  532.             spl(sr);
  533.             check_sigs();
  534.             sr = spl7();
  535.             sleepcond = 0;    /* possibly handled a signal, return */
  536.         }
  537.     }
  538.  
  539. /*
  540.  * kay: If _que & 0x100 != 0 then take curproc->wait_cond != cond as an
  541.  * indicatation that the wakeup has already happend before we actually
  542.  * go to sleep and return immediatly.
  543.  */
  544.  
  545.     if ((que == READY_Q && !sys_q[READY_Q]) ||
  546.         ((sleepcond != cond ||
  547.           (iwakecond == cond && cond) ||
  548.           (_que & 0x100 && curproc->wait_cond != cond)) &&
  549.          (!sys_q[READY_Q] || (newslice = 0, proc_clock)))) {
  550. /* we're just going to wake up again right away! */
  551.         iwakecond = 0;
  552.         spl(sr);
  553.         do_wakeup_things(sr, newslice);
  554.         return (onsigs != curproc->nsigs);
  555.     }
  556.  
  557. /*
  558.  * unless our time slice has expired (proc_clock == 0) and other
  559.  * processes are ready...
  560.  */
  561.     iwakecond = 0;
  562.     if (!newslice)
  563.         que = READY_Q;
  564.     else
  565.         curproc->wait_cond = cond;
  566.     add_q(que, curproc);
  567.  
  568. /* alright curproc is on que now...  maybe there's an interrupt pending
  569.  * that will wakeselect or signal someone
  570.  */
  571.     spl(sr);
  572.     if (!sys_q[READY_Q]) {
  573. /* hmm, no-one is ready to run. might be a deadlock, might not.
  574.  * first, try waking up any napping processes; if that doesn't work,
  575.  * run the root process, just so we have someone to charge time
  576.  * to.
  577.  */
  578.         wake(SELECT_Q, (long)nap);
  579.         sr = spl7();
  580.         if (!sys_q[READY_Q]) {
  581.             p = rootproc;        /* pid 0 */
  582.             rm_q(p->wait_q, p);
  583.             add_q(READY_Q, p);
  584.         }
  585.         spl(sr);
  586.     }
  587.  
  588. /*
  589.  * Walk through the ready list, to find what process should run next.
  590.  * Lower priority processes don't get to run every time through this
  591.  * loop; if "p->slices" is positive, it's the number of times that they
  592.  * will have to miss a turn before getting to run again
  593.  */
  594.  
  595. /*
  596.  * Loop structure:
  597.  *    while (we haven't picked anybody) {
  598.  *        for (each process) {
  599.  *            if (sleeping off a penalty) {
  600.  *                decrement penalty counter
  601.  *            }
  602.  *            else {
  603.  *                pick this one and break out of both loops
  604.  *            }
  605.  *        }
  606.  *    }
  607.  */
  608.     p = 0;
  609.  
  610.     while (!p) {
  611.         for (p = sys_q[READY_Q]; p; p = p->q_next) {
  612.             if (p->slices > 0)
  613.                 p->slices--;
  614.             else
  615.                 break;
  616.         }
  617.     }
  618.  
  619.     /* p is our victim */
  620.  
  621.     rm_q(READY_Q, p);
  622.  
  623.     spl(sr);
  624.  
  625.     if (save_context(&(curproc->ctxt[CURRENT]))) {
  626. /*
  627.  * restore per-process variables here
  628.  */
  629. #ifndef MULTITOS
  630. #ifdef FASTTEXT
  631.         if (!hardscroll)
  632.             *((void **)0x44eL) = curproc->logbase;
  633. #endif
  634. #endif
  635.         do_wakeup_things(sr, 1);
  636.         return (onsigs != curproc->nsigs);
  637.     }
  638. /*
  639.  * save per-process variables here
  640.  */
  641. #ifndef MULTITOS
  642. #ifdef FASTTEXT
  643.     if (!hardscroll)
  644.         curproc->logbase = *((void **)0x44eL);
  645. #endif
  646. #endif
  647.  
  648.     curproc->ctxt[CURRENT].regs[0] = 1;
  649.     curproc = p;
  650.     proc_clock = TIME_SLICE;    /* fresh time */
  651.     if ((p->ctxt[CURRENT].sr & 0x2000) == 0) {    /* user mode? */
  652.         leave_kernel();
  653.     }
  654.     assert(p->magic == CTXT_MAGIC);
  655.     change_context(&(p->ctxt[CURRENT]));
  656.     /* not reached */
  657.     return 0;
  658. }
  659.  
  660. /*
  661.  * wake(que, cond): wake up all processes on the given queue that are waiting
  662.  * for the indicated condition
  663.  */
  664.  
  665. INLINE static void
  666. do_wake(que, cond)
  667.     int que;
  668.     long cond;
  669. {
  670.     PROC *p;
  671. top:
  672.     for(p = sys_q[que]; p;) {
  673.         short s = spl7();
  674.         PROC *q;
  675.  
  676. /* check p is still on the right queue, maybe an interrupt just woke it... */
  677.         if (p->wait_q != que) {
  678.             spl(s);
  679.             goto top;
  680.         }
  681.         q = p;
  682.         p = p->q_next;
  683.         if (q->wait_cond == cond) {
  684.             rm_q(que, q);
  685.             add_q(READY_Q, q);
  686.         }
  687.         spl(s);
  688.     }
  689. }
  690.  
  691. void ARGS_ON_STACK 
  692. wake(que, cond)
  693.     int que;
  694.     long cond;
  695. {
  696.     if (que == READY_Q) {
  697.         ALERT("wake: why wake up ready processes??");
  698.         return;
  699.     }
  700.     if (sleepcond == cond)
  701.         sleepcond = 0;
  702.     do_wake(que, cond);
  703. }
  704.  
  705. /*
  706.  * iwake(que, cond, pid): special version of wake() for IO interrupt
  707.  * handlers and such.  the normal wake() would lose when its
  708.  * interrupt goes off just before a process is calling sleep() on the
  709.  * same condition (similar problem like with wakeselect...)
  710.  *
  711.  * use like this:
  712.  *    static ipid = -1;
  713.  *    static volatile sleepers = 0;    (optional, to save useless calls)
  714.  *    ...
  715.  *    device_read(...)
  716.  *    {
  717.  *        ipid = curproc->pid;    (p_getpid() for device drivers...)
  718.  *        while (++sleepers, (not ready for IO...)) {
  719.  *            sleep(IO_Q, cond);
  720.  *            if (--sleepers < 0)
  721.  *                sleepers = 0;
  722.  *        }
  723.  *        if (--sleepers < 0)
  724.  *            sleepers = 0;
  725.  *        ipid = -1;
  726.  *        ...
  727.  *    }
  728.  *
  729.  * and in the interrupt handler:
  730.  *    if (sleepers > 0) {
  731.  *        sleepers = 0;
  732.  *        iwake(IO_Q, cond, ipid);
  733.  *    }
  734.  *
  735.  * caller is responsible for not trying to wake READY_Q or other nonsense :)
  736.  * and making sure the passed pid is always -1 when curproc is calling
  737.  * sleep() for another than the waked que/condition.
  738.  */
  739.  
  740. void ARGS_ON_STACK 
  741. iwake(que, cond, pid)
  742.     int que;
  743.     long cond;
  744.     short pid;
  745. {
  746.     if (pid >= 0) {
  747.         short s = spl7();
  748.         if (iwakecond == cond) {
  749.             spl(s);
  750.             return;
  751.         }
  752.         if (curproc->pid == pid && !curproc->wait_q)
  753.             iwakecond = cond;
  754.         spl(s);
  755.     }
  756.     do_wake(que, cond);
  757. }
  758.  
  759. /*
  760.  * wakeselect(p): wake process p from a select() system call
  761.  * may be called by an interrupt handler or whatever
  762.  */
  763.  
  764. void ARGS_ON_STACK 
  765. wakeselect(param)
  766.     long param;
  767. {
  768.     PROC *p = (PROC *)param;
  769.     short s;
  770.     extern short select_coll;    /* in dosfile.c */
  771.  
  772.     s = spl7();    /* block interrupts */
  773.     if(p->wait_cond == (long)wakeselect ||
  774.        p->wait_cond == (long)&select_coll) {
  775.         p->wait_cond = 0;
  776.     }
  777.     if (p->wait_q == SELECT_Q) {
  778.         rm_q(SELECT_Q, p);
  779.         add_q(READY_Q, p);
  780.     }
  781.     spl(s);
  782. }
  783.  
  784. /*
  785.  * dump out information about processes
  786.  */
  787.  
  788. /*
  789.  * kludge alert! In order to get the right pid printed by FORCE, we use
  790.  * curproc as the loop variable.
  791.  *
  792.  * I have changed this function so it is more useful to a user, less to
  793.  * somebody debugging MiNT.  I haven't had any stack problems in MiNT
  794.  * at all, so I consider all that stack info wasted space.  -- AKP
  795.  */
  796.  
  797. #ifdef DEBUG_INFO
  798. static const char *qstring[] = {
  799.     "run", "ready", "wait", "iowait", "zombie", "tsr", "stop", "select"
  800. };
  801.  
  802. /* UNSAFE macro for qname, evaluates x 1, 2, or 3 times */
  803. #define qname(x) ((x >= 0 && x < NUM_QUEUES) ? qstring[x] : "unkn")
  804. #endif
  805.  
  806. #include "loadave.h"
  807.  
  808. unsigned long uptime = 0;
  809. unsigned long avenrun[3] = {0,0,0};
  810. short uptimetick = 200;
  811. static int number_running;
  812. static int one_min_ptr = 0, five_min_ptr = 0, fifteen_min_ptr = 0;
  813. static unsigned long sum1 = 0, sum5 = 0, sum15 = 0;
  814. static unsigned char one_min[SAMPS_PER_MIN];
  815. static unsigned char five_min[SAMPS_PER_5MIN];
  816. static unsigned char fifteen_min[SAMPS_PER_15MIN];
  817.  
  818. void
  819. DUMPPROC()
  820. {
  821. #ifdef DEBUG_INFO
  822.     PROC *p = curproc;
  823.  
  824.     FORCE("Uptime: %ld seconds Loads: %ld %ld %ld Processes running: %d",
  825.         uptime,
  826.         (avenrun[0]*100)/2048 , (avenrun[1]*100)/2048, (avenrun[2]*100/2048),
  827.          number_running);
  828.  
  829.     for (curproc = proclist; curproc; curproc = curproc->gl_next) {
  830.         FORCE("state %s PC: %lx BP: %lx",
  831.         qname(curproc->wait_q),
  832.         curproc->ctxt[SYSCALL].pc,
  833.         curproc->base);
  834.     }
  835.     curproc = p;        /* restore the real curproc */
  836. #endif
  837. }
  838.  
  839. unsigned long
  840. gen_average(sum, load_ptr, max_size)
  841.     unsigned long *sum;
  842.     unsigned char *load_ptr;
  843.     int max_size;
  844. {
  845.     int old_load, new_load;
  846.  
  847.     old_load = (int)*load_ptr;
  848.     new_load = number_running;
  849.     *load_ptr = (char)new_load;
  850.  
  851.     *sum += ((long) (new_load - old_load) * LOAD_SCALE);
  852.  
  853.     return (*sum / max_size);
  854. }
  855.  
  856. void
  857. calc_load_average()
  858. {
  859.     PROC *p;
  860.  
  861.     uptime++;
  862.     uptimetick += 200;
  863.  
  864.     if (uptime % 5) return;
  865.  
  866.     number_running = 0;
  867.     
  868.     for (p = proclist; p; p = p->gl_next)
  869.         if (p != rootproc)
  870.             if ((p->wait_q == 0) || (p->wait_q == 1))
  871.                 number_running++;
  872.  
  873.     avenrun[0] = gen_average(&sum1, &one_min[one_min_ptr++],
  874.                  SAMPS_PER_MIN);
  875.  
  876.     if (one_min_ptr == SAMPS_PER_MIN)
  877.         one_min_ptr = 0;
  878.  
  879.     avenrun[1] = gen_average(&sum5, &five_min[five_min_ptr++],
  880.                  SAMPS_PER_5MIN);
  881.  
  882.     if (five_min_ptr == SAMPS_PER_5MIN)
  883.         five_min_ptr = 0;
  884.  
  885.     avenrun[2] = gen_average(&sum15, &fifteen_min[fifteen_min_ptr++],
  886.                  SAMPS_PER_15MIN);
  887.  
  888.     if (fifteen_min_ptr == SAMPS_PER_15MIN)
  889.         fifteen_min_ptr = 0;
  890.  
  891. }
  892.  
  893.